/*
Copyright (C) 2008, 2009 Henrik Naess
Copyright (C) 2010 Gerhard Olsson

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using MatrixPlugin.Constants;
using MatrixPlugin.Integration;
using MatrixPlugin.Properties;
using MatrixPlugin.Utils;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Visuals.Fitness;
using ZoneFiveSoftware.Common.Visuals;
#if ST_2_1
#else
using ZoneFiveSoftware.Common.Visuals.Mapping;
#endif
using TrailsPlugin.UI.MapLayers;

namespace MatrixPlugin
{
    public partial class TableViewer : UserControl
    {
        #region constants

        //private const string INCLUDE_STOPPED_TIME_TEXT = "Include stopped time";
        //private const string EXCLUDE_STOPPED_TIME_TEXT = "Exclude stopped time";

        //Set with Theme
        private Color _colorPositive = Color.White;
        private Color _colorNegative = Color.White;

        #endregion constants      

        #region private variables

        private ViewerController _viewController;
        private readonly SettingsController _settingsController = SettingsController.Instance();
        private readonly Form _form = null;
        private bool isExpandedMode = false;

        /// <summary>Selected  (mouse over) column in grid</summary>
        private int _gridSelectedColumnIndex;

        /// <summary>Selected  (mouse over) row in grid</summary>
        private int _gridSelectedRowIndex;

        /// <summary>Last displayed tooltip</summary>
        private string _toolTip = String.Empty;

        /// <summary>When the settings was last read</summary>
        private DateTime _lastUpdated = DateTime.MinValue;

        private bool _hackForRowHeaderProblem;
        private bool m_showPage;
        private ITheme m_visualTheme =
#if ST_2_1
                MatrixPlugin.GetApplication().VisualTheme;
#else
                Plugin.GetApplication().SystemPreferences.VisualTheme;
#endif
        private System.Globalization.CultureInfo m_culture =
#if ST_2_1
                new System.Globalization.CultureInfo("en");
#else
                Plugin.GetApplication().SystemPreferences.UICulture;
#endif
        #endregion
#if ST_2_1
        private MapControlLayer layer { get { return MapControlLayer.Instance; } }
#else
        private ActivityDetailPage m_DetailPage = null;
        private IDailyActivityView m_view = null;
        //Default init, used for instance in popup
        private TrailPointsLayer m_layer = TrailPointsLayer.Instance(null);
#endif

#if !ST_2_1
        public TableViewer(ActivityDetailPage detailPage, IDailyActivityView view)
            : this()
        {
            m_DetailPage = detailPage;
            m_view = view;
            m_layer = TrailPointsLayer.Instance((IView)m_view);
        }
        //popup dialog
        public TableViewer(IDailyActivityView view)
            : this(true)
        {
            m_layer = TrailPointsLayer.Instance((IView)view);
        }
        public TableViewer(IActivityReportsView view)
            : this(true)
        {
            m_layer = TrailPointsLayer.Instance((IView)view);
        }
#endif
        public TableViewer(bool showPopup)
            : this()
        {
            //Theme and Culture must be set manually
            this.ThemeChanged(m_visualTheme);
            this.UICultureChanged(m_culture);
            btnExpand.Visible = false;

            _form = new Form();
            _form.Controls.Add(this);
            _form.MinimumSize = new Size(500, 300);
            _form.Icon = Icon.FromHandle(Resources.Windows_Table_32x32.GetHicon());
            this.Dock = System.Windows.Forms.DockStyle.Fill;
            _form.FormClosed += new FormClosedEventHandler(popupForm_FormClosed);
            _form.Show();
            _form.AutoSize = true;

            //ShowPage must be explicitly called
            ShowPage("");
        }

        public TableViewer()
        {
            InitializeComponent();
            InitControls();

            UpdateActivityInformation();
            ctxCalcInclStoppedTime.Checked = Settings.IncludeStoppedTime;
            ctxMatchAllPositions.Checked = Settings.MatchAllPositions;
            ctxMatchAllPositions.Visible = false; //not yet implemented
            ctxCompareToCurrent.Checked = Settings.CompareToCurrent;
            ctxHideEmptyRowsAndColumns.Checked = Settings.HideBlankRowsAndColumns;
            PopulateComboBoxes();
            SyncControlsOnPageWithSettings();
        }

        private void InitControls()
        {
            this.RefreshData_Event += new System.ComponentModel.PropertyChangedEventHandler(TableViewer_RefreshData_Event);

            this.btnRefresh.Text = "";
            this.btnRefresh.CenterImage = ZoneFiveSoftware.Common.Visuals.CommonResources.Images.Refresh16;
            this.btnSettings.Text = "";
            this.btnSettings.CenterImage = ZoneFiveSoftware.Common.Visuals.CommonResources.Images.Settings16;
#if ST_2_1
            btnExpand.Visible = false;
#else
            btnExpand.BackgroundImage = ZoneFiveSoftware.Common.Visuals.CommonResources.Images.View2PaneLowerHalf16;
#endif
            btnExpand.Text = "";
            ctxMenuItemClipboard.Image = ZoneFiveSoftware.Common.Visuals.CommonResources.Images.DocumentCopy16;
            this.ctxMenuItemRefActivity.Text = Properties.Resources.ctxReferenceActivity;
            this.comboBoxPositionGroups.ButtonImage = Properties.Resources.DropDown;
            this.comboBoxDataSource.ButtonImage = Properties.Resources.DropDown;
            this.comboBoxValue.ButtonImage = Properties.Resources.DropDown;
            this.comboBoxTempo.ButtonImage = Properties.Resources.DropDown;
            this.boxCategory.ButtonImage = Properties.Resources.DropDown;

            this.dataGrid.RowsDefaultCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleRight;
            //This will disable gradient header, but make them more like ST controls
            this.dataGrid.EnableHeadersVisualStyles = false;
            this.dataGrid.AdvancedColumnHeadersBorderStyle.All = DataGridViewAdvancedCellBorderStyle.Outset;
        }

        public void ThemeChanged(ITheme visualTheme)
        {
            m_visualTheme = visualTheme;
            this.comboBoxPositionGroups.ThemeChanged(visualTheme);
            this.comboBoxDataSource.ThemeChanged(visualTheme);
            this.comboBoxValue.ThemeChanged(visualTheme);
            this.comboBoxTempo.ThemeChanged(visualTheme);
            this.boxCategory.ThemeChanged(visualTheme);

            this.BackColor = visualTheme.Control;
            this.tableLayoutPanel1.BackColor = visualTheme.Control;
            this.panelFill.ThemeChanged(visualTheme);
            this.panelTop.ThemeChanged(visualTheme);
            this.dataGrid.BackgroundColor = visualTheme.Control;
            this.dataGrid.ForeColor = visualTheme.ControlText;
            this.dataGrid.GridColor = visualTheme.Border;
            this.dataGrid.DefaultCellStyle.BackColor = visualTheme.Window;
            this.dataGrid.RowHeadersDefaultCellStyle.BackColor = visualTheme.SubHeader;
            this.dataGrid.ColumnHeadersDefaultCellStyle.BackColor = visualTheme.SubHeader;
            //brush used for marking positive/negative
            _colorPositive = Color.AliceBlue;
            _colorNegative = Color.Beige;

            this.infoIcon.BackColor = visualTheme.SubHeader;
        }

        public void UICultureChanged(System.Globalization.CultureInfo culture)
        {
            m_culture = culture;
            this.groupBoxFilter.Text = Resources.tblFilter;
            //this.btnSettings.Text = Resources.Settings;
            this.ctxMenuItemCalculations.Text = Resources.Settings;
            this.ctxCompareToCurrent.Text = Resources.ctxCompareToCurrent;
            this.checkBoxCompareActivity.Text = Resources.ctxCompareToCurrent;
            this.ctxMatchAllPositions.Text = Resources.ctxMatchAllPositions;
            this.checkBoxMatchPositions.Text = Resources.ctxMatchAllPositions;
            this.ctxCalcInclStoppedTime.Text = Resources.ctxCalcInclStoppedTime;
            this.ctxRefreshMenuItem.Text = CommonResources.Text.ActionRefresh;
            this.labelDataSource.Text = Resources.tblData + ":";
            this.labelActivities.Text = Resources.ActivitiesText;
            this.ctxMenuItemActivities.Text = Resources.ActivitiesText;
            this.labelGroup.Text = Resources.tblGroup + ":";
            this.groupBoxDisplay.Text = Resources.tblDisplay;
            this.labelValue.Text = ZoneFiveSoftware.Common.Visuals.CommonResources.Text.LabelValue + ":";
            this.labelType.Text = ZoneFiveSoftware.Common.Visuals.CommonResources.Text.LabelType + ":";
            this.ctxMenuItemClipboard.Text = CommonResources.Text.ActionCopy;
            this.ctxDataGrid2Clipboard.Text = Resources.ctxDataGrid2Clipboard;
            this.ctxToolTip2ClipboardAsDelimited.Text = Resources.ctxToolTip2ClipboardAsDelimited;
            this.ctxToolTip2Clipboard.Text = Resources.ctxToolTip2Clipboard;
            this.ctxDisplayToolTip.Text = Resources.ctxDisplayToolTip;
            this.ctxMenuItemGoogleMaps.Text = Resources.ctxMenuItemGoogleMaps;
            //this.txtNoRowsAndColumns.Text = Resources.txtNoRowsAndColumns;
            this.ctxHideEmptyRowsAndColumns.Text = Resources.ctxHideEmptyRowsAndColumns;
            //Dynamic text, currently reset at UI change
            this.comboBoxDataSource.Text = DataSourceLabelProvider.GetText(MatrixViewController.dataSource);
            setCategoryLabel();
        }

        //The static configured activities
        //The used activities can differ, should be retrieved from the controller
        IList<IActivity> m_activities = new List<IActivity>();
        public IList<IActivity> Activities
        {
            get
            {
                return m_activities;
            }
            set
            {
                m_activities = value;
                MatrixViewController.Activities = value;
                MatrixViewController.dataSource = DataSource.CurrentSelection;

                RefreshData();
            }
        }

        private ViewerController MatrixViewController
        {
            get
            {
                if (_viewController == null)
                    _viewController = new ViewerController();

                return _viewController;
            }
        }

        public void ShowPage(string bookmark)
        {
            m_showPage = true;
            MatrixViewController.PositionGroup = null;
            RefreshData(false);
#if ST_2_1
            layer.ShowPage = true;
#else
            m_layer.ShowPage(bookmark);
#endif
        }

        public bool HidePage()
        {
#if ST_2_1
            layer.ShowPage = false;
#else
            m_layer.HidePage();
#endif
            //Reset position groups
            MatrixViewController.Reset();
            return true;
        }

        void popupForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            this.HidePage();
        }

        private event System.ComponentModel.PropertyChangedEventHandler RefreshData_Event;
        private void RefreshDataChanged(string propertyName)
        {
            if (RefreshData_Event != null)
            {
                RefreshData_Event(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
            setCategoryLabel();
        }
        void TableViewer_RefreshData_Event(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke((System.ComponentModel.PropertyChangedEventHandler)TableViewer_RefreshData_Event, sender, e);
            }
            else
            {
                if (m_showPage)
                {
                    RefreshData();
                }
            }
        }

        private void RefreshData()
        {
            RefreshData(true);
        }

        private void RefreshData(bool showToolTip)
        {
            if (m_showPage)
            {
#if !ST_2_1
                m_layer.HidePage(); //defer updates
#endif
                m_layer.TrailPoints = new List<TrailsPlugin.Data.TrailGPSLocation>();
                //Debug.WriteLine("MatrixPlugin.TableViewer: RefreshData() @" + DateTime.Now);
                dataGrid.Visible = false;
                dataGrid.DataSource = null;
                if (!String.IsNullOrEmpty(comboBoxPositionGroups.Text) && m_showPage)
                {
                    bool changed = false;
                    int numberOfActivities = MatrixViewController.NumberOfActivities;
                    if (MatrixViewController.dataSource == DataSource.UniqueRoutes)
                        changed = MatrixViewController.SetActivityBasedOnUniqueRoute();
                    else if (MatrixViewController.dataSource == DataSource.CurrentSelection)
                        changed = MatrixViewController.SetActivityToSelectedActivity(Activities);
                    else if (MatrixViewController.dataSource == DataSource.CurrentActivity)
                        changed = MatrixViewController.SetActivityToBaseActivity();
                    else if (MatrixViewController.dataSource == DataSource.AllActivities)
                        changed = MatrixViewController.SetActivityToAllActivities();
                    else if (MatrixViewController.dataSource == DataSource.ActivitiesThisYear)
                        changed = MatrixViewController.SetActivityToActivityYear(DateTime.Now.Year);
                    else if (MatrixViewController.dataSource == DataSource.ActivitiesThisDay)
                        changed = MatrixViewController.SetActivityToBaseActivityDate();
                    else
                        Debug.Fail(string.Format("Unknown data filter ({0})", comboBoxDataSource.Text));

                    if (MatrixViewController.dataSource != DataSource.CurrentActivity &&
                        MatrixViewController.dataSource != DataSource.CurrentSelection)
                    {
                        changed |= MatrixViewController.SetActivityToCategory();
                    }

                    DataTable results = MatrixViewController.Calculate(progressBarLoading);
                    dataGrid.DataSource = results;
                    UpdateUIAfterResultHasChanged();

                    if (showToolTip)
                    {
                        ShowNumberOfActivitiesToolTip(changed);
                    }
                }
            }
        }

        private void UpdateUIAfterResultHasChanged()
        {
            SetTableHeaders();
            UpdateActivityInformation();
            toolTipInfo.SetToolTip(infoIcon, string.Format(
                Resources.TableViewer_NowUsesText, MatrixViewController.GetNumberOfActivitiesText()));

            int numberOfActivities = MatrixViewController.NumberOfActivitiesWithGPSdata;
            ctxMenuItemGoogleMaps.Enabled = (numberOfActivities > 0);
            comboBoxTempo.Enabled = (numberOfActivities > 1);
            SetCompareActivityState(numberOfActivities);

            //Add the activities to the menu
            this.ctxMenuItemRefActivity.DropDownItems.Clear();
            foreach (IActivity act in MatrixViewController.Activities)
            {
                //It takes extremely long time to add many activities to the menu//Abort at some reasonable limit
                if (this.ctxMenuItemRefActivity.DropDownItems.Count < 50
                    || act.Equals(MatrixViewController.BaseActivity))
                {
                    string tt = DistanceInfoList.GetToolTipForActivity(act, act.Name, act.ReferenceId,
                            act.TotalDistanceMetersEntered, act.TotalTimeEntered, act.StartTime,
                            false, 0,
                            false, "",
                            false, "", "", "");
                    ToolStripMenuItem childMenuItem = new ToolStripMenuItem(tt);
                    childMenuItem.Tag = act.ReferenceId;
                    if (act.Equals(MatrixViewController.BaseActivity))
                    {
                        childMenuItem.Checked = true;
                    }
                    else
                    {
                        childMenuItem.Checked = false;
                    }
                    this.ctxMenuItemRefActivity.DropDownItems.Add(childMenuItem);
                    childMenuItem.Click += new System.EventHandler(this.ctxRefActivityItemActivities_Click);
                }
            }
            IList<TrailsPlugin.Data.TrailGPSLocation> points = new List<TrailsPlugin.Data.TrailGPSLocation>();
            if (null != MatrixViewController.PositionGroup &&
                null != MatrixViewController.PositionGroup.MatrixPoints &&
                MatrixViewController.PositionGroup.MatrixPoints.Count > 0)
            {
                foreach (MatrixPoint point in MatrixViewController.PositionGroup.MatrixPoints)
                {
                    points.Add(new TrailsPlugin.Data.TrailGPSLocation(point.GpsPoint.LatitudeDegrees, point.GpsPoint.LongitudeDegrees, point.Name));
                }
                m_layer.HighlightRadius = (float)Settings.MaxRadius;
            }
            m_layer.TrailPoints = points;
            if (m_showPage)
            {
#if ST_2_1
                layer.ShowPage = _showPage;//Refresh
#else
                m_layer.ShowPage("");//Refresh
#endif
            }
            progressBarLoading.Visible = false;
            SetHideBlankColumnsAndRows(Settings.HideBlankRowsAndColumns);
        }

        private void SetHideBlankColumnsAndRows(bool hide)
        {
            bool visibleRows = false; //Are any rows at all visible?
            Settings.HideBlankRowsAndColumns = hide;
            if (null != dataGrid.DataSource)
            {
                DataTable dataTable = dataGrid.DataSource as DataTable;
                int hideRowIndex = -1;
                int unSelectRowIndex = -1;
                for (int rowIndex = 0; rowIndex < dataTable.Rows.Count; rowIndex++)
                {
                    if (!(DataTableUtility.RowIsEmpty(dataTable.Rows[rowIndex])))
                    {
                        visibleRows = true;
                    }
                    if (hide && DataTableUtility.RowIsEmpty(dataTable.Rows[rowIndex]))
                    {
                        if (null == dataGrid.CurrentRow || rowIndex != dataGrid.CurrentRow.Index)
                        {
                            dataGrid.Rows[rowIndex].Visible = false;
                        }
                        else
                        {
                            //Cannot hide this row as it is selected, try later
                            hideRowIndex = rowIndex;
                        }
                    }
                    else
                    {
                        dataGrid.Rows[rowIndex].Visible = true;
                        unSelectRowIndex = rowIndex;
                    }
                }
                for (int columnIndex = 0; columnIndex < dataTable.Columns.Count; columnIndex++)
                {
                    if (hide && DataTableUtility.ColumnIsEmpty(dataTable, columnIndex))
                    {
                        dataGrid.Columns[columnIndex].Visible = false;
                    }
                    else
                    {
                        dataGrid.Columns[columnIndex].Visible = true;
                    }
                }
                //Hide selected but empty row
                if (hideRowIndex >= 0 && unSelectRowIndex >= 0 &&
                    (null == dataGrid.CurrentRow || hideRowIndex != dataGrid.CurrentRow.Index))
                {
                    dataGrid.Rows[unSelectRowIndex].Selected = true;
                    dataGrid.Rows[hideRowIndex].Visible = false;
                }
            }
            dataGrid.Visible = visibleRows;
            if (!visibleRows)
            {
                if (_viewController.PositionGroup == null || _viewController.PositionGroup.MatrixPoints == null || _viewController.PositionGroup.MatrixPoints.Count == 0)
                {
                    this.txtNoRowsAndColumns.Text = Resources.txtNoMatrixPoints;
                }
                else
                {
                    this.txtNoRowsAndColumns.Text = Resources.txtNoRowsAndColumns;
                }
            }
            txtNoRowsAndColumns.Visible = !visibleRows;
            infoIcon.Visible = true;// visibleRows;
        }

        private void UpdateActivityInformation()
        {
            string text = MatrixViewController.GetNumberOfActivitiesText();
            if (_form != null)
                _form.Text = string.Format(Resources.tblActivityInfo, text);

            labelActivities.Text = text;
        }
        private void UpdatePositionGroups()
        {
            PositionGroup defaultPositionInXml = _settingsController.DefaultPositionGroup;

            if (!string.IsNullOrEmpty(Settings.PositionGroup) && _settingsController.PositionGroups.ContainsKey(Settings.PositionGroup))
                comboBoxPositionGroups.Text = Settings.PositionGroup;
            else if (defaultPositionInXml.Name != null && _settingsController.PositionGroups.ContainsKey(defaultPositionInXml.Name))
                comboBoxPositionGroups.Text = defaultPositionInXml.Name;
            else if (_settingsController.PositionGroups.Count > 0)
            {
                Dictionary<string,PositionGroup>.Enumerator posEnumerator = _settingsController.PositionGroups.GetEnumerator();
                posEnumerator.MoveNext();
                if (posEnumerator.Current.Value != null)
                {
                    comboBoxPositionGroups.Text = posEnumerator.Current.Value.Name;
                }
            }
        }

        private void PopulateComboBoxes()
        {
            UpdatePositionGroups();
            comboBoxTempo.Text = General.TempoTypeLabelProvider.GetText(Settings.TempoType);
            comboBoxValue.Text = General.DataValueLabelProvider.GetText(Settings.DataValue);
            setCategoryLabel();
        }

        #region Tooltip

        private void dataGrid_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e)
        {
            _gridSelectedColumnIndex = e.ColumnIndex;
            _gridSelectedRowIndex = e.RowIndex;

            e.ToolTipText = MatrixViewController.ToolTip(_gridSelectedColumnIndex, _gridSelectedRowIndex);
            _toolTip = e.ToolTipText;
        }

        #endregion

        #region Clipboard integration

        private void ctxDataGrid2Clipboard_Click(object sender, EventArgs e)
        {
            StringBuilder builder = new StringBuilder();
            foreach (DataGridViewColumn column in dataGrid.Columns)
                builder.Append("\t" + column.HeaderText);

            foreach (DataGridViewRow row in dataGrid.Rows)
            {
                builder.Append(Environment.NewLine);
                builder.Append(row.HeaderCell.Value);
                foreach (DataGridViewCell cell in row.Cells)
                    builder.Append("\t" + cell.Value);
            }

            Clipboard.SetText(builder.ToString());
            ShowCtxToolTip(Resources.CtxToolTip);
        }

        /// <summary>
        /// Copy tool tip to clipboard. Expects that dataGrid_CellToolTipTextNeed is triggered before this method
        /// </summary>
        private void ctxToolTip2Clipboard_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(_toolTip);
            ShowCtxToolTip(Resources.CtxToolTip);
        }

        private void ctxToolTip2ClipboardAsDelimited_Click(object sender, EventArgs e)
        {
            string text = String.Empty;
            if (_gridSelectedColumnIndex >= 0 && _gridSelectedRowIndex >= 0)
                text = MatrixViewController.ToolTipAsDelimitedField(_gridSelectedColumnIndex, _gridSelectedRowIndex, General.Delimiter);

            try
            {
                if (text.Length > 0)
                    Clipboard.SetText(text);
                else
                    Clipboard.Clear();

                ShowCtxToolTip(Resources.CtxToolTip);
            }
            catch (ExternalException)
            {
                MessageDialog.Show("Copy to clipboard failed", "Clipboard", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private static void ShowCtxToolTip(string text)
        {
            // TODO: toolTipGrid.Show(text, ((System.Windows.Forms.ContainerControl)(this)).focusedControl.Location.X, , 1000);
        }

        #endregion

        #region Google Maps integration

        /// <summary>
        /// Add links to Google Maps for row- and column headers
        /// </summary>
        private void SetTableHeaders()
        {
            for (int columnNumber = 0; columnNumber < MatrixViewController.ColumnHeaderText.Count; columnNumber++)
            {
                if (dataGrid.Columns.Count > columnNumber)
                {
                    DataGridViewColumn column = dataGrid.Columns[columnNumber];
                    column.SortMode = DataGridViewColumnSortMode.NotSortable;
                    column.HeaderCell.Value = MatrixViewController.ColumnHeaderText[columnNumber].Name;
                    //column.HeaderCell.ToolTipText = string.Format("Display {0}, {1} in Google Maps",
                    //                                              MatrixViewController.ColumnHeaderText[columnNumber].LatitudeInUSDecimalFormat,
                    //                                              MatrixViewController.ColumnHeaderText[columnNumber].LongitudeInUSDecimalFormat);
                }
            }
            for (int rowNumber = 0; rowNumber < MatrixViewController.RowHeaderText.Count; rowNumber++)
            {
                if (dataGrid.Rows.Count > rowNumber)
                {
                    DataGridViewRow row = dataGrid.Rows[rowNumber];
                    row.HeaderCell.Value = MatrixViewController.RowHeaderText[rowNumber].Name;
                    //row.HeaderCell.ToolTipText = string.Format("Display {0}, {1} in Google Maps",
                    //                                           MatrixViewController.RowHeaderText[rowNumber].LatitudeInUSDecimalFormat,
                    //                                           MatrixViewController.RowHeaderText[rowNumber].LongitudeInUSDecimalFormat);
                }
            }
        }

        private void dataGrid_RowHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DisplayGoogleMapsForRow(e.RowIndex);
        }

        private void dataGrid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            DisplayGoogleMapsForRow(e.ColumnIndex);
        }

        private void ctxGEarth1_Click(object sender, EventArgs e)
        {
            DisplayGoogleMapsForRow(_gridSelectedRowIndex);
        }

        private void ctxGEarth2_Click(object sender, EventArgs e)
        {
            DisplayGoogleMapsDirection(_gridSelectedColumnIndex, _gridSelectedRowIndex);
        }

        private void DisplayGoogleMapsDirection(int column, int row)
        {
            if (column >= 0 && column < MatrixViewController.ColumnHeaderText.Count &&
                row >= 0 && row < MatrixViewController.RowHeaderText.Count)
            {
                ExtendedGPSPoint columnGPSPoint = MatrixViewController.ColumnHeaderText[column];
                ExtendedGPSPoint rowGPSPoint = MatrixViewController.RowHeaderText[row];
                Google.ShowGoogleMapFromTo(columnGPSPoint, rowGPSPoint);
            }
        }

        private void DisplayGoogleMapsForRow(int row)
        {
            if (row >= 0 && row < MatrixViewController.RowHeaderText.Count)
            {
                ExtendedGPSPoint rowGPSPoint = MatrixViewController.RowHeaderText[row];
                Google.ShowGoogleMap(rowGPSPoint);
            }
        }

        #endregion

        #region Handle refresh of data based on user click

        private void ctxDisplayToolTip_Click(object sender, EventArgs e)
        {
            GenericMessageBox tooltipForm = new GenericMessageBox(Resources.ToolTip, _toolTip,
                                                                  Plugin.GetApplication().VisualTheme);
            tooltipForm.Width = 1280;
            tooltipForm.ShowDialog();
        }

        /************************************************/
        private void comboBoxPositionGroups_ButtonClicked(object sender, EventArgs e)
        {
            TreeListPopup treeListPopup = new TreeListPopup();
            treeListPopup.ThemeChanged(m_visualTheme);
            treeListPopup.Tree.Columns.Add(new TreeList.Column());

            treeListPopup.Tree.RowData = MatrixViewController.GetListForPositionGroups();
            treeListPopup.Tree.LabelProvider = new PositionGroupLabelProvider();

            if (MatrixViewController.GetListForPositionGroups().Contains(MatrixViewController.PositionGroup))
            {
                treeListPopup.Tree.Selected = new object[] { MatrixViewController.PositionGroup };
            }
            treeListPopup.ItemSelected += delegate(object sender2, TreeListPopup.ItemSelectedEventArgs e2)
                {
                    try
                    {
                        MatrixViewController.PositionGroup = ((PositionGroup)(e2).Item);
                        Settings.PositionGroup = MatrixViewController.PositionGroup.Name;
                        comboBoxPositionGroups.Text = Settings.PositionGroup;
                        SyncControlsOnPageWithSettings();
                        RefreshDataChanged("");
                    }
                    catch (KeyNotFoundException)
                    {
                        MessageDialog.Show("Settings (position group) for Matrix was changed, please redo your actions");
                    }
                };
            treeListPopup.Popup(this.comboBoxPositionGroups.Parent.RectangleToScreen(this.comboBoxPositionGroups.Bounds));
        }

        private void comboBoxDataSource_ButtonClicked(object sender, EventArgs e)
        {
            TreeListPopup treeListPopup = new TreeListPopup();
            treeListPopup.ThemeChanged(m_visualTheme);
            treeListPopup.Tree.Columns.Add(new TreeList.Column());

            treeListPopup.Tree.RowData = DataSourceLabelProvider.getValues(TrailsPlugin.Integration.UniqueRoutes.UniqueRouteIntegrationEnabled);
            treeListPopup.Tree.LabelProvider = new DataSourceLabelProvider();

            treeListPopup.Tree.Selected = new object[] { MatrixViewController.dataSource };
            treeListPopup.ItemSelected += delegate(object sender2, TreeListPopup.ItemSelectedEventArgs e2)
        {
            try
            {
                MatrixViewController.dataSource = (DataSource)((TreeListPopup.ItemSelectedEventArgs)e2).Item;
                comboBoxDataSource.Text = DataSourceLabelProvider.GetText(MatrixViewController.dataSource);
                RefreshDataChanged("");
            }
            catch (KeyNotFoundException)
            {
                MessageDialog.Show("Settings (data source) for Matrix was changed, please redo your actions");
            }
        };

            treeListPopup.Popup(this.comboBoxDataSource.Parent.RectangleToScreen(this.comboBoxDataSource.Bounds));
        }


        private void addNode(IActivityCategory category, System.Collections.IList parentCategories)
        {
            if (parentCategories == null)
                if (category.SubCategories.Count > 0) parentCategories.Add(category);
            foreach (IActivityCategory subcategory in category.SubCategories)
            {
                addNode(subcategory, parentCategories);
            }
        }

        private void boxCategory_ButtonClicked(object sender, EventArgs e)
        {
            TreeListPopup treeListPopup = new TreeListPopup();
            treeListPopup.ThemeChanged(m_visualTheme);
            treeListPopup.Tree.Columns.Add(new TreeList.Column());

            IList<object> list = new List<object>();
            foreach (IActivityCategory category in Plugin.GetApplication().Logbook.ActivityCategories)
            {
                list.Add(category);
            }
            list.Add(Properties.Resources.UseAllCategories);

            treeListPopup.Tree.RowData = list;
            treeListPopup.Tree.ContentProvider = new ActivityCategoryContentProvider(list);
            treeListPopup.Tree.ShowPlusMinus = true;
            treeListPopup.FitContent = false;

            if (Settings.SelectedCategory != null)
            {
                treeListPopup.Tree.Selected = new object[] { Settings.SelectedCategory };
                treeListPopup.Tree.Expanded = new object[] { Settings.SelectedCategory };
            }
            System.Collections.IList parentCategories = new System.Collections.ArrayList();
            foreach (IActivityCategory category in Plugin.GetApplication().Logbook.ActivityCategories)
            {
                addNode(category, parentCategories);
            }
            treeListPopup.Tree.Expanded = parentCategories;

            treeListPopup.ItemSelected += delegate(object sender2, TreeListPopup.ItemSelectedEventArgs e2)
            {
                if (e2.Item is IActivityCategory)
                {
                    Settings.SelectedCategory = (IActivityCategory)e2.Item;
                }
                else
                {
                    Settings.SelectedCategory = null;
                }
                setCategoryLabel();
                RefreshDataChanged("");
            };
            treeListPopup.Popup(this.boxCategory.Parent.RectangleToScreen(this.boxCategory.Bounds));
        }

        private void comboBoxTempo_ButtonClicked(object sender, EventArgs e)
        {
            TreeListPopup treeListPopup = new TreeListPopup();
            treeListPopup.ThemeChanged(m_visualTheme);
            treeListPopup.Tree.Columns.Add(new TreeList.Column());

            treeListPopup.Tree.RowData = General.TempoTypeLabelProvider.getValues();
            treeListPopup.Tree.LabelProvider = new General.TempoTypeLabelProvider();
            
            treeListPopup.Tree.Selected = new object[] { Settings.TempoType };
            treeListPopup.ItemSelected += delegate(object sender2, TreeListPopup.ItemSelectedEventArgs e2)
        {
            try
            {
                Settings.TempoType = (General.TempoType)(e2).Item;
                comboBoxTempo.Text = General.TempoTypeLabelProvider.GetText(Settings.TempoType);
                RefreshDataChanged("");
            }
            catch (KeyNotFoundException)
            {
                MessageDialog.Show("Settings (tempo) for Matrix was changed, please redo your actions");
            }
        };
            treeListPopup.Popup(this.comboBoxTempo.Parent.RectangleToScreen(this.comboBoxTempo.Bounds));
        }

        private void comboBoxValue_ButtonClicked(object sender, EventArgs e)
        {
            TreeListPopup treeListPopup = new TreeListPopup();
            treeListPopup.ThemeChanged(m_visualTheme);
            treeListPopup.Tree.Columns.Add(new TreeList.Column());

            treeListPopup.Tree.RowData = General.DataValueLabelProvider.getValues();
            treeListPopup.Tree.LabelProvider = new General.DataValueLabelProvider();

            treeListPopup.Tree.Selected = new object[] { Settings.DataValue };
            treeListPopup.ItemSelected += delegate(object sender2, TreeListPopup.ItemSelectedEventArgs e2)
            {
                try
                {
                    Settings.DataValue = (General.DataValue)((TreeListPopup.ItemSelectedEventArgs)e2).Item;
                    comboBoxValue.Text = General.DataValueLabelProvider.GetText(Settings.DataValue);
                    RefreshDataChanged("");
                }
                catch (KeyNotFoundException)
                {
                    MessageDialog.Show("Settings (value) for Matrix was changed, please redo your actions");
                }
            };
            treeListPopup.Popup(this.comboBoxValue.Parent.RectangleToScreen(this.comboBoxValue.Bounds));
        }

        /************************************************/
        void ctxMenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            this.ctxMenuGrid.SuspendLayout();
            if (_gridSelectedRowIndex < 0)
            {
                ctxGMapsPos.Enabled = false;
            }
            else
            {
                ctxGMapsPos.Enabled = true;
            }
            if (_gridSelectedColumnIndex < 0 ||
                _gridSelectedRowIndex < 0 ||
                _gridSelectedColumnIndex == _gridSelectedRowIndex)
            {
                ctxGMapsDir.Enabled = false;
            }
            else
            {
                ctxGMapsDir.Enabled = true;
            }
            if (_gridSelectedColumnIndex >= 0 && _gridSelectedRowIndex >= 0 &&
                _gridSelectedColumnIndex < this.dataGrid.ColumnCount &&
                _gridSelectedRowIndex < this.dataGrid.RowCount)
            {
                //Update Google texts
                ExtendedGPSPoint columnGPSPoint = MatrixViewController.ColumnHeaderText[_gridSelectedColumnIndex];
                ExtendedGPSPoint rowGPSPoint = MatrixViewController.RowHeaderText[_gridSelectedRowIndex];
                ctxGMapsPos.Text = string.Format(Resources.ctxGMapsPos_Text, rowGPSPoint.Name);
                ctxGMapsDir.Text = string.Format(Resources.ctxGMapsDir_Text, rowGPSPoint.Name,
                                                columnGPSPoint.Name);

                this.ctxMenuItemActivities.DropDownItems.Clear();
                //Add the activities to the menu
                IDictionary<string, string> tt = MatrixViewController.ToolTipActivity(
                    _gridSelectedColumnIndex, _gridSelectedRowIndex, "");

                foreach (KeyValuePair<string, string> act in tt)
                {
                    ToolStripMenuItem childMenuItem = new ToolStripMenuItem(act.Value);
                    //ToolTipActivity uses the activity as the key, only one returned
                    childMenuItem.Tag = act.Key;
                    this.ctxMenuItemActivities.DropDownItems.Add(childMenuItem);
                    childMenuItem.Click += new System.EventHandler(this.ctxMenuItemActivities_Click);
                }
            }
            this.ctxMenuGrid.ResumeLayout(true);
            e.Cancel = false;
        }

        private void ctxCompareToCurrent_CheckStateChanged(object sender, EventArgs e)
        {
            Settings.CompareToCurrent = ctxCompareToCurrent.Checked;
            RefreshData();
        }
        private void ctxMatchAllPositions_CheckStateChanged(object sender, EventArgs e)
        {
            Settings.MatchAllPositions = ctxMatchAllPositions.Checked;
            RefreshData();
        }
        private void ctxCalcInclStoppedTime_CheckStateChanged(object sender, EventArgs e)
        {
            Settings.IncludeStoppedTime = ctxCalcInclStoppedTime.Checked;
            RefreshData();
        }
        private void checkBoxCompareBase_CheckedChanged(object sender, EventArgs e)
        {
            Settings.CompareToCurrent = checkBoxCompareActivity.Checked;
            RefreshData();
        }
        private void checkBoxMatchPositions_CheckedChanged(object sender, EventArgs e)
        {
            Settings.MatchAllPositions = checkBoxMatchPositions.Checked;
            RefreshData();
        }

        private void ctxMenuItemActivities_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem sourceMenuItem = (ToolStripMenuItem)sender;
            if (sourceMenuItem != null && sourceMenuItem.Tag != null)
            {
                //Open the activities - ST3 could open for instance Trails
                Guid view = GUIDs.OpenView;
                string bookmark = "id=" + sourceMenuItem.Tag;
                Plugin.GetApplication().ShowView(view, bookmark);
            }
        }
        private void ctxRefActivityItemActivities_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem sourceMenuItem = (ToolStripMenuItem)sender;
            if (sourceMenuItem != null && sourceMenuItem.Tag != null)
            {
                string refId = (string)sourceMenuItem.Tag;
                foreach (IActivity act in MatrixViewController.Activities)
                {
                    if (refId.Equals(act.ReferenceId))
                    {
                        MatrixViewController.BaseActivity = act;
                    }
                }

                RefreshData();
            }
        }

        private void ctxRefreshToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RefreshData();
        }

        private void ctxHideEmptyRowsAndColumns_Click(object sender, EventArgs e)
        {
            Settings.HideBlankRowsAndColumns = !Settings.HideBlankRowsAndColumns;
            ctxHideEmptyRowsAndColumns.Checked = Settings.HideBlankRowsAndColumns;
            SetHideBlankColumnsAndRows(Settings.HideBlankRowsAndColumns);
        }
        private void btnExpand_Click(object sender, EventArgs e)
        {
#if !ST_2_1
            if (m_DetailPage != null)
            {
                if (isExpandedMode)
                {
                    //Expanded mode to normal

                    btnExpand.BackgroundImage = ZoneFiveSoftware.Common.Visuals.CommonResources.Images.View2PaneLowerHalf16;
                    m_DetailPage.PageMaximized = false;
                    isExpandedMode = false;
                }
                else
                {
                    btnExpand.BackgroundImage = ZoneFiveSoftware.Common.Visuals.CommonResources.Images.View3PaneLowerLeft16;
                    m_DetailPage.PageMaximized = true;
                    isExpandedMode = true;
                }
            }
#endif
        }
        #endregion

        private void setCategoryLabel()
        {
            setCategoryLabel(Settings.SelectedCategory);
        }
        private void setCategoryLabel(IActivityCategory category)
        {
            boxCategory.Text = getCategory(category, null);
            if (MatrixViewController.dataSource == DataSource.CurrentActivity ||
                MatrixViewController.dataSource == DataSource.CurrentSelection ||
                MatrixViewController.dataSource == DataSource.UniqueRoutes)
            {
                this.boxCategory.Enabled = false;
            }
            else
            {
                this.boxCategory.Enabled = true;
            }
        }
        //Recursively get category
        private string getCategory(IActivityCategory iActivityCategory, string p)
        {
            if (iActivityCategory == null)
            {
                if (p != null)
                {
                    return p;
                }
                return Properties.Resources.UseAllCategories;
            }
            if (p == null) return getCategory(iActivityCategory.Parent,
                                        iActivityCategory.Name);
            return getCategory(iActivityCategory.Parent,
                                iActivityCategory.Name + ": " + p);
        }

        private void SyncControlsOnPageWithSettings()
        {
            PositionGroup positionGroup = MatrixViewController.PositionGroup;
            if (MatrixViewController.PositionGroup != null)
            {
                //Some settings could be set in the positionGroups
                //Propagate as default settings - it is the latest the user sets
                if (positionGroup.ValidDataValue)
                {
                    Settings.DataValue = positionGroup.DataValue;
                }
                if (positionGroup.ValidTempoType)
                {
                    Settings.TempoType = positionGroup.TempoType;
                }
                if (null != positionGroup.HideBlankColumnsAndRows)
                {
                    Settings.HideBlankRowsAndColumns = (bool)positionGroup.HideBlankColumnsAndRows;
                }
                if (null != positionGroup.IncludeStoppedTime)
                {
                    Settings.IncludeStoppedTime = (bool)positionGroup.IncludeStoppedTime;
                }
            }
        }

        private void SetCompareActivityState(int numberOfActivities)
        {
            checkBoxCompareActivity.Enabled = (MatrixViewController.HasBaseActivity);
            ctxCompareToCurrent.Enabled = (MatrixViewController.HasBaseActivity);
        }

        private void dataGrid_Paint(object sender, PaintEventArgs e)
        {
            if (!_hackForRowHeaderProblem)
            {
                SetTableHeaders();
                _hackForRowHeaderProblem = true;
                if (Settings.HideBlankRowsAndColumns)
                {
                    SetHideBlankColumnsAndRows(Settings.HideBlankRowsAndColumns);
                }
            }
        }

        private void dataGrid_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
        {
            if (e.RowIndex >= 0 && e.ColumnIndex >= 0)
            {
                if (Settings.CompareToCurrent && MatrixViewController.HasBaseActivity)
                {
                    String cellValue = e.FormattedValue.ToString();
                    if (cellValue.Contains("(-"))
                    {
                        e.CellStyle.BackColor = _colorNegative;
                    }
                    else if (cellValue.Contains("(+"))
                    {
                        e.CellStyle.BackColor = _colorPositive;
                    }
                }
            }
        }
        private void dataGrid_SelectionChanged(object sender, EventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;

            ////User selected WHOLE ROW (by clicking in the margin)
            //if (dgv.SelectedRows.Count > 0)
            //    MessageDialog.Show(dgv.SelectedRows[0].Cells[0].Value.ToString());

            ////User selected a cell (show the first cell in the row)
            //if (dgv.SelectedCells.Count > 0)
            //    MessageDialog.Show(dgv.Rows[dgv.SelectedCells[0].RowIndex].Cells[0].Value.ToString());

            //User selected a cell, show that cell
            if (dgv.SelectedCells.Count > 0)
            {
                DataTable dataTable = dataGrid.DataSource as DataTable;
                //int hideRowIndex = -1;
                //int unSelectRowIndex = -1;
                for (int rowIndex = 0; rowIndex < dataTable.Rows.Count; rowIndex++)
                {
                    int i;
                    for (i = 0; i < (dgv.SelectedCells.Count); i++)
                    {
                        //dataGrid.cell
                        //  dgv.DataSource[dgv.SelectedCells[i].ColumnIndex,dgv.SelectedCells[i].ColumnIndex]
                        IList<TrailsPlugin.Data.TrailGPSLocation> points = new List<TrailsPlugin.Data.TrailGPSLocation>();
                        foreach (MatrixPoint point in MatrixViewController.PositionGroup.MatrixPoints)
                        {
                            points.Add(new TrailsPlugin.Data.TrailGPSLocation(point.GpsPoint.LatitudeDegrees, point.GpsPoint.LongitudeDegrees, point.Name));
                        }
                        m_layer.HighlightRadius = (float)Settings.MaxRadius;
                        m_layer.TrailPoints = points;

                        MatrixPoint p = MatrixViewController.PositionGroup.MatrixPoints[dgv.SelectedCells[i].ColumnIndex];
                    }
                    //MessageDialog.Show(dgv.SelectedCells[0].Value.ToString());
                }
            }
        }

        private bool IsRowAndColumnTheSame(DataGridViewCellPaintingEventArgs e)
        {
            string columnName = dataGrid.Columns[e.ColumnIndex].Name;
            string rowName = dataGrid.Rows[e.RowIndex].HeaderCell.Value as String;
            return String.Compare(columnName, rowName, StringComparison.InvariantCultureIgnoreCase) == 0;
        }

        private void ShowNumberOfActivitiesToolTip(bool changed)
        {
            if (changed)
            {
                ShowToolTip(string.Format(Resources.TableViewer_NowUsesText, MatrixViewController.GetNumberOfActivitiesText()));
            }
            else
            {
                ShowToolTip(string.Format(Resources.TableViewer_StillUsesText, MatrixViewController.NumberOfActivities));
            }
        }

        private void ShowToolTip(string text)
        {
            const int displayTimeForToolTip = 3000;
            toolTipInfo.Show(text, this, labelActivities.Top, labelActivities.Left, displayTimeForToolTip);
        }
    }
}